
#include "jncTypeInfo.h"

typedef enum { BASIC, POINTER, ARRAY } ReqType;

ReqType typeOf(const jncTypei& t) 
{
#define JBASIC BOOST_PP_SEQ_SIZE(REMOVE_VOID(BOOST_PP_ADD(JINC_MAX_ARG, 2), ENUM2) ENUM1 BOOST_PP_SEQ_FOR_EACH(JNCSENUM, ~, ENUM1))
#define JPOINTER JBASIC + BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_FOR_EACH(JNCPENUM, ~, ENUM1) BOOST_PP_SEQ_FOR_EACH(JNCPENUM, ~, ENUM3))
  
  return (t > JBASIC)?(t > JPOINTER)?ARRAY:POINTER:BASIC;
}

FnInfo getFnParameters(const CplInfo& c) {
  std::list<HandlerTable::HandlerInfo>* namespacetbl(AllocNamespaceTable()->getTable());
  typedef std::list<HandlerTable::HandlerInfo>::iterator ItObjectDb;
  ItObjectDb i = namespacetbl->begin(); 
  for(; i != namespacetbl->end(); i++)
    if(i->memberfnts.find(c.getId()) != i->memberfnts.end())
      break;
  if(i == namespacetbl->end())
    return NULL;
  FnInfo fn(i->memberfnts.find(c.getId())->second);
  // Detect Type requested and wrap if necessary
//   jncTypei tmp(*fn->ptsignature->begin());
//   if(typeOf(tmp) == POINTER)
//     {

//     }
//   else if(typeOf(tmp) == ARRAY)
//     {

//     }
  return fn;
}

std::string fnName(const std::list<std::string>& names) {
  std::string tmp(*names.begin());
  tmp += "(";
  for(std::list<std::string>::const_iterator i = ++names.begin();;i++)
    if(i != names.end())
      tmp += std::string(*i + ",");
    else
      break;
  return (std::string(tmp.begin(), --tmp.end()) + ")");
}

void
RtmInfo::setReturn()
{
  assert(getState() == COMPLETE);
  std::vector<jncTypev> arg;
  try 
    {
      for(std::vector<RtmInfo>::iterator i = argv.begin(); i != argv.end(); i++)
	{
	  try {
	    i->setReturn();
	    arg.insert(arg.end(), (i->getResult()));
	  }
	  catch(boost::bad_any_cast& e) {
	    FnInfo fn_param(getFnParameters(i->getId()));
	    char pos[3];
	    sprintf((char*)&pos, "%d", (i - argv.begin()));
	    std::string msg("In ");
	    std::string tmp = (fn_param)?fnName(*fn_param->pssignature):(std::string("argument ") + (char*)pos);
	    msg += (std::string(tmp + ":\n") + ((RnException*)&e)->what());
	    throw RnException(((RnException*)&e)->getCode(), msg.c_str(), e);
	  }
	}
      if(ret.empty())
	ret = gReturnCode(ptr_ob->CallMember(CallBackParam(setter, arg)));
    }
  catch(boost::bad_any_cast& e)
    {
      FnInfo fn_param(getFnParameters(getId()));
      std::string msg("In ");
      msg += (std::string(fnName(*fn_param->pssignature)) + ":\n") + ((RnException*)&e)->what();
      throw RnException(((RnException*)&e)->getCode(), msg.c_str(), e);
    }
}
